ALB のカスタムドメインへの HTTP 接続を HTTPS へリダイレクトする構成を AWS CDK で実装する

ALB のカスタムドメインへの HTTP 接続を HTTPS へリダイレクトする構成を AWS CDK で実装する

Clock Icon2024.08.31

こんにちは、製造ビジネステクノロジー部の若槻です。

Web サイトや API の HTTPS 化での後方互換性の維持などのために、HTTP から HTTPS へのリダイレクト設定を行いたい場合があります。

Application Load Balancer(ALB) では、リダイレクトアクション をリスナーに設定することにより、ポートやプロトコルのリダイレクトが設定可能となります。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-listeners.html#redirect-actions

今回は、ALB のカスタムドメインへの HTTP 接続を HTTPS へリダイレクトする構成を AWS CDK で実装してみました。

試してみた

前提

カスタムドメインの Route 53 Hosted Zone および、ACM 証明書は作成済みである前提とします。

今回は前回の下記ブログで実装した環境を利用します。

https://dev.classmethod.jp/articles/using-aws-cdk-to-attach-console-created-acm-certificate-to-alb-for-custom-domain/

リダイレクトを設定しない場合

まずはリダイレクトを設定しない場合の挙動を確認します。

CDK の実装

次のように ALB を作成し、443 ポートにリスナーのみを追加した実装です。

lib/cdk-sample-stack.ts
import {
  aws_ec2 as ec2,
  aws_elasticloadbalancingv2 as elbv2,
  Stack,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * Application Load Balancer の作成
     */
    const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
      vpc: new ec2.Vpc(this, 'VPC'),
      internetFacing: true,
    });

    /**
     * 443 ポートリスナーの作成
     */
    alb.addListener('Listener', {
      port: 443,
      certificates: [
        {
          certificateArn: process.env.CERTIFICATE_ARN || '',
        },
      ],
      defaultAction: elbv2.ListenerAction.fixedResponse(200, {
        contentType: 'text/plain',
        messageBody: 'Hello, CDK!',
      }),
    });
  }
}

動作確認

https:443 へはアクセスできますが、http:80 へのアクセスはタイムアウトとなりました。想定通りの挙動です。

$ curl https://${HOSTNAME}/ --connect-timeout 3
HTTP/2 200
server: awselb/2.0
date: Sat, 31 Aug 2024 05:25:37 GMT
content-type: text/plain; charset=utf-8
content-length: 11

$ curl http://${HOSTNAME}/ --connect-timeout 3
curl: (28) Failed to connect to <ホスト名> port 80 after 3004 ms: Timeout was reached

http:80 から https:443 へのリダイレクトを設定する

CDK の実装

続いて、addRedirect メソッドを使用してリスナーに http:80 から https:443 へのリダイレクトを設定します。

lib/cdk-sample-stack.ts
import {
  aws_ec2 as ec2,
  aws_elasticloadbalancingv2 as elbv2,
  Stack,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * Application Load Balancer の作成
     */
    const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
      vpc: new ec2.Vpc(this, 'VPC'),
      internetFacing: true,
    });

    /**
     * 443 ポートリスナーの作成
     */
    alb.addListener('Listener', {
      port: 443,
      certificates: [
        {
          certificateArn: process.env.CERTIFICATE_ARN || '',
        },
      ],
      defaultAction: elbv2.ListenerAction.fixedResponse(200, {
        contentType: 'text/plain',
        messageBody: 'Hello, CDK!',
      }),
    });

    /**
     * 80 から 443 ポートへのリダイレクト設定
     */
    alb.addRedirect({
      sourcePort: 80,
      sourceProtocol: elbv2.ApplicationProtocol.HTTP,
      targetPort: 443,
      targetProtocol: elbv2.ApplicationProtocol.HTTPS,
    });
  }
}

CDK Diff で差分を確認すると、リスナーが追加され、またセキュリティグループに 80 ポートへのアクセスを許可する設定が追加されていることがわかります。

$ npx cdk diff
Stack CdkSampleStack
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)
Security Group Changes
┌───┬──────────────────────────────┬─────┬──────────┬─────────────────┐
│   │ Group                        │ Dir │ Protocol │ Peer            │
├───┼──────────────────────────────┼─────┼──────────┼─────────────────┤
│ + │ ${ALB/SecurityGroup.GroupId} │ In  │ TCP 80   │ Everyone (IPv4) │
└───┴──────────────────────────────┴─────┴──────────┴─────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Resources
[+] AWS::ElasticLoadBalancingV2::Listener ALB/Redirect80To443 ALBRedirect80To4430753BB69
[~] AWS::EC2::SecurityGroup ALB/SecurityGroup ALBSecurityGroup8B8624F8
 └─ [~] SecurityGroupIngress
     └─ @@ -5,5 +5,12 @@
        [ ]     "FromPort": 443,
        [ ]     "IpProtocol": "tcp",
        [ ]     "ToPort": 443
        [+]   },
        [+]   {
        [+]     "CidrIp": "0.0.0.0/0",
        [+]     "Description": "Allow from anyone on port 80",
        [+]     "FromPort": 80,
        [+]     "IpProtocol": "tcp",
        [+]     "ToPort": 80
        [ ]   }
        [ ] ]

✨  Number of stacks with differences: 1

一つのメソッドでセキュリティグループのルールまで細かく制御してくれるなんて L2 Construct の面目躍如ですね。

動作確認

前述の実装を CDK Deploy します。

CloudFormation のダッシュボードを確認すると、スタック上で ALB にリスナーが作成されています。

ALB のダッシュボードを見ると、リダイレクト用の HTTP リスナー及びルールが作成されています。

カスタムドメインへ接続してみると、https:443 への直接アクセスは引き続き成功し、また http:80 へのアクセスは https:443 にちゃんとリダイレクトされる挙動となりました。

$ curl https://${HOSTNAME}/ --head --connect-timeout 3
HTTP/2 200
server: awselb/2.0
date: Sat, 31 Aug 2024 05:23:33 GMT
content-type: text/plain; charset=utf-8
content-length: 11

$ curl http://${HOSTNAME}/ --head --connect-timeout 3
HTTP/1.1 301 Moved Permanently
Server: awselb/2.0
Date: Sat, 31 Aug 2024 05:23:39 GMT
Content-Type: text/html
Content-Length: 134
Connection: keep-alive
Location: https://<ホスト名>:443/

CDK でのリダイレクト設定の別解

先ほど使用した addRedirect は手続き的な書き方でリダイレクト用のリスナーを追加できるメソッドでしたが、addListener メソッドで宣言的に書くことも可能です。

lib/cdk-sample-stack.ts
import {
  aws_ec2 as ec2,
  aws_elasticloadbalancingv2 as elbv2,
  Stack,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * Application Load Balancer の作成
     */
    const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
      vpc: new ec2.Vpc(this, 'VPC'),
      internetFacing: true,
    });

    /**
     * 443 ポートリスナーの作成
     */
    alb.addListener('Listener', {
      port: 443,
      certificates: [
        {
          certificateArn: process.env.CERTIFICATE_ARN || '',
        },
      ],
      defaultAction: elbv2.ListenerAction.fixedResponse(200, {
        contentType: 'text/plain',
        messageBody: 'Hello, CDK!',
      }),
    });

    /**
     * 80 から 443 ポートへのリダイレクト設定 (別解)
     */
    alb.addListener('HTTPListener', {
      port: 80,
      defaultAction: elbv2.ListenerAction.redirect({
        port: '443',
        protocol: elbv2.ApplicationProtocol.HTTPS,
      }),
    });
  }
}

お好きな方をどうぞ。

おわりに

ALB のカスタムドメインへの HTTP 接続を HTTPS へリダイレクトする構成を AWS CDK で実装してみました。

参考になれば幸いです。

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.